#pragma once
#include <string>
#include <boost/array.hpp>

enum Mnemonic {
	/*! "No Operation". Does nothing. A, B and R are ignored. This is the default Mnemonic. ArgA, ArgB and Ret could be used to store values */
	NOOP = 0,

// arithmetic
	/*! Addition. Puts A+B to R. Values very well might overflow */
	ADD,

	/*! Subtraction. Puts (A - B) to R. Values may over/under flow */
	SUB,

	/*! Multiplication. Puts (A * B) to R. Values may overflow/underflow */
	MULT,

	/*! Division. Puts (A / B) to R. Dividing by zero will result in zero (not error). Value may under/overflow */
	DIV,

	/*! Minimium. Puts the smaller of argA and argB to Ret address. */
	MIN,

	/*! Maximium. Puts the larger of argA and argB to Ret address */
	MAX,

	/*! Modulo. Returns A modulo B, unlike the C(++) language -- the result is guaranteed to have the same sign-ness as B. */
	MOD,

// bitwise
	/*! Bitwise addition */
	AND,

	/*! Bitwise or */
	OR,

	/*! Bitwise exclusive or */
	XOR,

	/*! Bitwise rightshift argA's value argB places. Put result in ret. */
	LSHIFT,

	/*! Bitwise leftshift argA's value argB palces. Put result in ret. */
	RSHIFT,

// flow control
	/*! Equal. If A == B, return 1 (for true), otherwise returns 0 (for false) */
	EQ,

	/*! Not Equal. If A != B, return 1 (for true), otherwise returns 0 (for false) */
	NEQ,

	/*! Less than. If A < B returns 1 (for true), otherwise returns 0 (for false) */
	LT,

	/*! Less than or equal. If A <= B returns 1 (for true) otherwise returns 0 (for false) */
	LTE,

	/*! Greater than. If A > B returns 1 (for true) otherwise returns 0 (for false). */
	GT,

	/*! Greater than or equal. If A >= B returns 1 (for true) otherwise returns 0 (for false)  */
	GTE,

	/*! Conditional Jump. If A is true (not zero), control goes to B. Otherwise control continues as normal. Returns nothing */
	IF,
// reflection
	/*! Get the identifier of the instruction at A. B is ignored. This might at first seem useless, why would you ever want to get an identifier of something we already know? But it is because of the look up rules, if an exact identifier match cannot be found lore uses the one the first one with an identifer greater than that. */
	GETI,

	/*! Get the opcode of the instruction at A. B is ignored. */
	GETO,

	/*! Get the first argument (A) of the instruction at A. B is ignored. */
	GETA,

	/*! Get the second argument (B) of the instruction at A. B is ignored. */
	GETB,

	/*! Get the third argument (R) of the instruction at A. B is ignored. */
	GETR,

	/*! Before. Get's the identifier of the instruction immediately before A. By "immediately before" it means in an execution sense. i.e. The instruction that would be executed after this one. argB and ret is ignored. */
	BEFORE,

	/*! After. Get's the identifier of the instruction immediately after A. By "immediately after" it means in an execution sense. i.e. The instruction that would be executed after this one. argB and ret is ignored. */
	AFTER,

	/*! Create's a new instruction before the item at A. The new instructions opcode is set to B. The new instruction has an auto-generated non-conflicting identifier, which is the return value. This process MUST BE determanstic for a given run! Suggested method: pick the first not-in-use identifier. A seeded random number generated is acceptable, but ghetto  */
	CREATE_BEFORE,

	/*! Create's a new instruction after the item at A. The new instructions opcode is is set to B. The new instruction has an auto-generated non-conflicting identifier, which is the return value. This process MUST BE determanstic for a given run! Suggested method: pick the first not-in-use identifier. A seeded random number generated is acceptable, but ghetto  */
	CREATE_AFTER,

	/*! Removes the instruction at A. Ignores B and R. Returns nothing. */
	REMOVE,

// io
	/*! Returns a random integer. Ignores A and B. */
	RAND,

	/*! Pulls from A'th input collection and gets the B'th integer (1 indexed). The zero is magic. Accessing a zero'd collection returns auto-generated collection with what collections are available. Getting the 0th item from a collection returns a value that says how many ints in the collection. */
	READ,

	/* Finishes execution. A is used as the return code. B and R are ignored. Returns nothing. */
	EXIT,
	NUMBER_OF_MNEMONICS // NOT ACTUALLY A MNEMONIC!!!
};

boost::array<Mnemonic, NUMBER_OF_MNEMONICS> all_mnemonics();
std::string show(Mnemonic);
bool has_return(Mnemonic);

